import axios from 'axios'
import _ from 'lodash';
import md5 from 'md5';
import $ from 'jquery'
import store from '@/store'
import Vue from 'vue'
import {
  randomWord, getSign, getQueryString
} from './tools'
import router from '@/router'
import {message} from 'ant-design-vue'
import VuexStore from '@/store'
console.log(window.localStorage.getItem('vuexStoragePad'))
console.log("=======")
const appid = '40bd001563085fc35165329ea1ff5c5ecbdbbeef'
const app_secret = '3f666c39681952deec3d2e2e673ad78450fa8af810653852fb7f18eb240c521c'
// const baseURL = 'https://e-school.sse100.cn'
// const baseURL = 'https://newyxp.sse100.com'
const baseURL = 'https://e-school.yixuepai100.com'
const prefix = '/api'
const requestList = []
let loadings = 0
let loadMaskTimer = null
// 取消列表
const CancelToken = axios.CancelToken
let sources = {}
axios.defaults.timeout = 1000 * 20
axios.defaults.withCredentials = false
axios.defaults.headers['Content-Type'] = 'application/json;charset=UTF-8'
axios.defaults.headers['appid'] = appid
axios.defaults.baseURL = `${baseURL}${prefix}`

// 加载BSync-START
const REQTIMEOUT = 20 * 1000
window._zRoomCount = 0
window._zInRoomCount = 0
const _zBcKey = window._zBcKey = 'vuexStoragePad'
const _zLcKey = window._zLcKey = 'yxp_bs'
let class_mode = getQueryString('class_mode') || 'PAD_121'
// 等待bs异步操作加入房间、获取对象等
const waitForSync = window.waitForSync = async (cmd = 'OBJECT', maxt = 20 * 1000) => {
  let curt = 0
  let tms = 20
  // 班型控制
  if(['PAD_SINGLE'].indexOf(class_mode) !== -1) return true
  if(cmd == 'OBJECT'){
    while (typeof window.___browserSync___ === 'undefined' && curt < maxt) {
      await delay(tms)
      curt += tms
    }
  }else if(cmd == 'ROOM'){
    while (typeof window._zInRoomOver === 'undefined' && curt < maxt) {
      await delay(tms)
      curt += tms
    }
  }else{
    while (typeof window[cmd] === 'undefined' && curt < maxt) {
      await delay(tms)
      curt += tms
    }
  }
}
const delay = ms => new Promise((resolve) => setTimeout(() => {
  resolve()
}, ms))
const isBSync = window.isBSync = function () {
  let wbs = window.___browserSync___
  if(!!wbs && typeof wbs._zrequests === 'undefined') window.___browserSync___._zrequests = {}
  return window.___browserSync___
}
let isController = window.isController = function () {
  let BSync = isBSync()
  return BSync ? (typeof BSync._zcontroller === 'undefined' ? false : BSync._zcontroller) : true
}
const BSyncStart = async function (er, cf) {
  await waitForSync()
  let BSync = isBSync()
  if (BSync && cf.method === 'post') {
    cf._url = /^http/.test(cf.url) ? cf.url : `${cf.baseURL}${cf.url}`
    if (!isController()) {
      // 设置为一个空地址
      cf.url = `${baseURL}${prefix}/test/checkonline`
    }
  }
}
const BSyncEnd = async function (er, res) {
  await waitForSync('ROOM')
  let BSync = isBSync()
  let config = res.config
  if (BSync && config.method === 'post') {
    if (!er) {
      let tms = 50
      let total = REQTIMEOUT
      let curt = 0
      // 移除url中sign参数
      let rkey = (config._url || config.url).replace(/[\\?|&]?sign=[^&]*/g, '')
      rkey = md5(rkey)
      if (!isController()) {
        while (!BSync._zrequests[rkey]) {
          if (curt >= total) break
          await delay(tms)
          curt += tms
        }
        if (BSync._zrequests[rkey]) {
          res.data = BSync._zrequests[rkey].data
          delete BSync._zrequests[rkey]
        } else {
          res.data = {}
        }
      } else {
        total -= 5 * 1000
        // 是否为主数据传输状态
        let _zNeedSyncCount = Number(BSync._zNeedSyncCount) || 0
        if(_zNeedSyncCount > 0){
          while (window._zInRoomCount < _zNeedSyncCount) {
            if (curt >= total) break
            await delay(tms)
            curt += tms
          }
        }
        // 提交数据
        BSync.socket.emit('requests', {key: rkey, data: res.data})
      }
    }
  }
}
;(async () => {
  // 等待bs初始化加载
  await waitForSync()
  // 等待登录状态同步
  // await waitForSync('_zParentUser')
  console.log('bs.等待.预加载完成')
  // 开始初始化
  let BSync = isBSync()
  // 课程初始化开始
  if(/PAD_SINGLE/i.test(class_mode)){
    let store = window.localStorage
    let roomKey = _zBcKey.replace(/pad/i, '')
    store.getItem(roomKey) && store.setItem(_zBcKey, store.getItem(roomKey))
    VuexStore.commit('setLogin', JSON.parse(store.getItem(roomKey)))
  }
  if (BSync) {
    setTimeout(() => {
      typeof BSync._zNeedSyncCount !== 'undefined' && (BSync._zNeedSyncCount = 0)
    }, REQTIMEOUT)
    // 同步处理
    const _zDoSync = window._zDoSync = async function (roomCount) {
      await delay(2 * 1000)
      let maxt = 20 * 1000
      let curt = 0
      let tms = 50
      let _zNeedSyncCount = Number(BSync._zNeedSyncCount) || 0
      if(!isController() || roomCount <= 1) return false
      else{
        if(_zNeedSyncCount > 0){
          // 恢复默认状态
          roomCount >= _zNeedSyncCount && setTimeout(() => {
            BSync._zNeedSyncCount = 0
          }, 1000 * 3)
          // window._zInRoomCount >= _zNeedSyncCount && (BSync._zNeedSyncCount = 0)
          return false
        }
      }
      // 同步localstorage数据
      for(let lckey of [_zBcKey, 'paperData', 'dataList', 'beforeWord', 'afterWord', 'sceneData', 'superRead', 'reverseWrod']){
        let lcv = window.localStorage.getItem(lckey)
        !!lcv && BSync.socket.emit('sync:local', {k: lckey, v: lcv})
      }
      // 同步刷新页面
      BSync.socket.emit('sync:location', {url: window.location.href})
      // 等待房间人数为1时刷新自己
      window._zRoomCount = roomCount
      while (window._zRoomCount != 1 && curt < maxt) {
        await delay(tms)
        curt += tms
      }
      if(window._zRoomCount == 1){
        BSync._zNeedSyncCount = roomCount
        window.location.reload()
      }
    }
    ;(function () {
      let lcBs = JSON.parse(window.localStorage.getItem(_zLcKey)) || {}
      for(let k of ['_zcontroller', '_zNeedSyncCount']){
        Object.defineProperty(BSync, k, {
          configurable: true,
          get: function () {
            return lcBs[k]
          },
          set: function (nval) {
            lcBs[k] = nval
            window.localStorage.setItem(_zLcKey, JSON.stringify(lcBs))
          }
        })
      }
    })()
    // 开始业务处理
    let _zParentUser = window._zParentUser || JSON.parse(window.localStorage.getItem(_zBcKey.replace(/pad/i, '')) || window.localStorage.getItem(_zBcKey))
    if(_zParentUser){
      if(_zParentUser.userInfo.is_assist == 0){// 学生
        BSync._zcontroller = ['PAD_SMALL'].indexOf(class_mode) !== -1 ? false : true
      }else{// 老师
        BSync._zcontroller = ['PAD_SMALL'].indexOf(class_mode) !== -1 ? true : false
      }
      // 处理隐身用户-监课
      if(getQueryString('is_check')) BSync._zcontroller = false
    }
    BSync.socket.on('requests', function (data) {
      data.key && !isController() && (BSync._zrequests[data.key] = data)
    })
    BSync.socket.on('sync:local', function (data) {
      window.localStorage.setItem(data.k, data.v)
    })
    BSync.socket.on('sync:location', function (data) {
      let a = []
      let b = []
      let c = window.location.href
      let e = ''
      let zfp = window.ZFPATH
      a = data.url.split(zfp)
      b = c.split(zfp)
      // 设置更新时间
      if(getQueryString('is_check')) window.localStorage.setItem('yxp_sync_time', new Date().getTime())
      // 组装url
      if(1 || (/^file/.test(data.url) && /^http/.test(c)) || (/^http/.test(data.url) && /^file/.test(c))){
        data.url = `${b[0]}${b.length>1?zfp:''}${a[1]||''}`
      }
      if(data.url === c){
        window.location.reload()
      }else{
        e = `?r=${new Date().getTime()}&`
        getQueryString('is_check') && (e += `is_check=${getQueryString('is_check')}&`)
        getQueryString('access_token') && (e += `access_token=${getQueryString('access_token')}&`)
        data.url = data.url.replace(/\?(r=[^&]+&)?/, e)
        window.location.href = data.url
      }
    })
    BSync.socket.on('sync:cmd', function (data) {
      let cmd = data.cmd || '_zDoSync'
      cmd == '_zDoSync' && _zDoSync(data.roomCount)
    })
    BSync.socket.on('user:joined', function (data) {
      console.log('user:joined', data)
      window._zInRoomCount = data.roomCount
      // 如果为数据控制者触发同步
      data.role == 0 && _zDoSync(data.roomCount)
    })
    BSync.socket.on('user:leaved', function (data) {
      console.log('user:leaved', data)
      // 更新房间人数
      window._zRoomCount = data.roomCount
    })
    BSync.socket.on('scroll', function (data) {
      // 判断有没有滚动条
      if (data.tagName === 'INPUT') return
      let el = document.getElementsByTagName(data.tagName)[data.index]
      let clickBody = $(el).closest('.js-clickbody')
      if(el && el.scrollHeight <= el.clientHeight){
        let pobj = document.getElementsByClassName("ant-popover-open")[0]
        if(pobj){
          if (clickBody) {
            clickBody.click()
          } else {
            pobj.click()
          }
        }
      }
    })
    BSync.socket.on('sync:cmd', function (data) {
      if(data.cmd == 'ROUTER_CHANGE'){
        let checkSync = window._yxpSync_
        let isCheck = Number(getQueryString('is_check')) || 0
        if(isCheck && !checkSync){
          BSync.socket.emit('sync:cmd', {
            cmd: '_zDoSync'
          })
        }
      }
    })
    // 文档由隐藏切换显示触发
    // document.addEventListener("visibilitychange", () => {
    //   if(document.visibilityState == 'visible'){
    //     // 自动同步
    //     // BSync.socket.emit('sync:cmd', {
    //     //   broadcast: true
    //     // })
    //   }
    // }, false);
    window._zSocketRegEvent = true
  }
})()
// 加载BSync-END
let isFormData = (v) => {
  return Object.prototype.toString.call(v) === '[object FormData]';
}
// const TOKEN = window.localStorage.getItem('access_token')
function pruneEmpty(obj) {
  if (isFormData(obj)) return obj
  return function prune(current) {
    _.forOwn(current, function (value, key) {
      if(value === 0){
        current[key] = '0'
        value = '0'
      }
      if ((_.isUndefined(value) || _.isNull(value) || _.isNaN(value) ||
        (_.isString(value) && _.isEmpty(value)) ||
        (_.isObject(value) && _.isEmpty(prune(value)))) && value !== 0) {
        delete current[key];
      }
    });
    console.log(current);
    // remove any leftover undefined values from the delete
    // operation on an array
    if (_.isArray(current)) _.pull(current, undefined);
    return current;

  }(_.cloneDeep(obj)); // Do not modify the original object, create a clone instead
}
function syncReqBlockClose() {
  // 等待渲染完成结束冻结层
  setTimeout(() => {
    document.getElementById('yxp-loading-mask').style.display = 'none'
    loadMaskTimer && clearTimeout(loadMaskTimer)
  }, 200)
}

axios.interceptors.request.use(async (config) => {
  console.log('开始请求了')
  loadMaskTimer && clearTimeout(loadMaskTimer)
  Vue.prototype.$loading.show()
  if (!document.getElementById('yxp-loading-mask')) {
    let div = document.createElement('div')
    div.style.background = 'rgba(0,0,0,0)'
    div.style.position = 'fixed'
    div.style.left = 0
    div.style.top = 0
    div.style.right = 0
    div.style.bottom = 0
    div.style.display = 'block'
    div.style.zIndex = 99900
    div.id = 'yxp-loading-mask'
    document.body.appendChild(div)
  } else {
    document.getElementById('yxp-loading-mask').style.display = 'block'
  }
  loadMaskTimer = setTimeout(() => {
    syncReqBlockClose()
  }, 10*1000)
  console.log(config)
    let timestamp = new Date().valueOf(),
    noncestr = randomWord(true, 16, 32)
    let {access_token} = JSON.parse(window.localStorage.getItem(_zBcKey) || window.localStorage.getItem(_zBcKey.replace(/pad/i, ''))) || {}
    if (access_token && config.url !=="/common/uploadonline") {
      config.data = Object.assign({}, config.data, {access_token})
    }
    let sign = getSign(config.data, {appid, appsecret: app_secret, noncestr, timestamp })
    if (config.url.includes('searchword?word')) {
      config.url = `${config.url}`
    } else {
      config.url = `${config.url}${config.url.indexOf('?')==-1?'?':'&'}sign=${sign}`
    }
    config.headers['timestamp'] = timestamp
    config.headers['noncestr'] = noncestr
    //config.headers['Content-Type'] = 'application/x-www-form-urlencoded'
    // config.headers['access_token'] = window.localStorage.getItem('access_token')
    const request = JSON.stringify(config.url) + JSON.stringify(config.data)
    config.cancelToken = new CancelToken((cancel) => {
      sources[request] = cancel
    })
    if (requestList.includes(request)) {
      sources[request]('取消重复请求')
    } else {
      requestList.push(request)
    }
    if (BSyncStart) {
      await BSyncStart(null, config)
    }
    return config
}, function (error) {
  console.log(error, 'error', 'request')
  Vue.prototype.$loading.hide()
  syncReqBlockClose()
  return Promise.reject(error)
})

axios.interceptors.response.use(async function (response) {
  console.log(response)
  Vue.prototype.$loading.hide()
  console.log(_.get(response, 'data.code', '0'))
  if (BSyncEnd) {
    await BSyncEnd(null, response)
  }
  const request = JSON.stringify(response.config.url) + JSON.stringify(response.config.data)
  requestList.splice(requestList.findIndex(item => item === request), 1)

  if (requestList.length === 0) {
    console.log('请求完成了')
    // 整体请求完成
    console.log(document.getElementById('yxp-loading-mask'))
    syncReqBlockClose()
  }
  // if (_.get(response, 'data', '') && _.get(response, 'data.code', '')) {
  //   let errorCode = response.data.code
  // }

  if (10001 === +_.get(response, 'data.code', '0')) {
    router.push('/')
    if (['PAD_SINGLE'].indexOf('PAD_SINGLE') !== -1) {
      window.location.href = window.location.origin + '/#/mycourse'
      // store.commit("setLoginModal", true)
    }
    if(window.parent) {
      window.parent.postMessage(
        {
          cmd: "reLogin",
          msg: "ok",
        }, '*'
      )
    }
    message.error('登录')
    syncReqBlockClose()
  } else {
    syncReqBlockClose()
  }
  return response
}, function (error) {
  Vue.prototype.$loading.hide()
  syncReqBlockClose()
  if (_.get(error, 'response.data', '') && _.get(error, 'response.data.code', '')) {
    // let errorCode = +error.response.data.code
    // switch (errorCode) {
    // }
  }

  if (error.response && error.response.data && error.response.data.msg) {
   // message.error(error.response.data.msg)
  }
  requestList.length = 0
  if (axios.isCancel(error)) {
    requestList.length = 0
    console.log('取消请求')
    // throw new axios.Cancel('cancel request')
  } else {
    // 请求失败
    // const request = JSON.stringify(error.config.url) + JSON.stringify(error.config.data)
    // requestList.splice(requestList.findIndex(item => item === request), 1)
  }
  return Promise.reject(error)
})

const request = function (method, {
  url,
  params,
  data,
  // headers,
  config
}) {
  return new Promise((resolve, reject) => {
    let resultData = pruneEmpty(data)
    let resultParams = pruneEmpty(params)
    axios({
      method: method.toLowerCase(),
      ...config,
      params: resultParams,
      url,
      data: resultData
    }).then(response => {
      resolve(response.data)
    }, err => {
      if (err.Cancel) {
        console.log(err)
      } else {
        reject(err)
      }
    }).catch(err => {
      reject(err)
    })
  })
}
const http = {
  get(paramBean) {
    let {
      data
    } = paramBean
    paramBean.params = data
    return request('get', paramBean)
  },
  post(paramBean) {
    console.log(paramBean)
    return request('post', paramBean)
  },
  put(paramBean) {
    return request('put', paramBean)
  },
  delete(paramBean) {
    return request('delete', paramBean)
  }
}
export {
  sources,
  http
}
